package com.joysuch.wwyt.patrol.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.base.Splitter;
import com.joysuch.wwyt.bp.entity.BPNFCLocation;
import com.joysuch.wwyt.bp.entity.BpDeviceFacilityCollection;
import com.joysuch.wwyt.bp.entity.BpProductionFacility;
import com.joysuch.wwyt.bp.enums.ProductionFacilityStates;
import com.joysuch.wwyt.bp.repository.BPNFCLocationDao;
import com.joysuch.wwyt.bp.repository.BpDeviceFacilityCollectionDao;
import com.joysuch.wwyt.bp.service.BpNFCLocationService;
import com.joysuch.wwyt.bp.service.BpProductionFacilityService;
import com.joysuch.wwyt.common.constant.Constant;
import com.joysuch.wwyt.core.bean.BaseNfcCardBean;
import com.joysuch.wwyt.core.constant.Constants;
import com.joysuch.wwyt.core.enums.DeleteFlag;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.patrol.constant.CheckResultStatus;
import com.joysuch.wwyt.patrol.entity.*;
import com.joysuch.wwyt.patrol.entity.bean.StatPlanTitleSearchBean;
import com.joysuch.wwyt.patrol.entity.dto.SimplePointRecordDto;
import com.joysuch.wwyt.patrol.entity.dto.SimpleRecordResultDto;
import com.joysuch.wwyt.patrol.entity.vo.*;
import com.joysuch.wwyt.patrol.enums.DataTypeEnum;
import com.joysuch.wwyt.patrol.mapper.PatrolDataTypeMapper;
import com.joysuch.wwyt.patrol.mapper.PatrolRecordMapper;
import com.joysuch.wwyt.patrol.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author heqifeng
 * @since 2022-03-03
 */
@Service
public class PatrolRecordServiceImpl extends ServiceImpl<PatrolRecordMapper, PatrolRecord> implements PatrolRecordService {
    @Autowired
    private PatrolRecordMapper recordMapper;
    @Autowired
    private PatrolCheckItemService checkItemService;
    @Autowired
    private PatrolRecordItemService recordItemService;
    @Autowired
    private PatrolCheckPointService pointService;
    @Autowired
    private BaseUserDao userDao;
    @Autowired
    private PatrolTaskService taskService;
    @Autowired
    private BpNFCLocationService bpNFCLocationService;
    @Autowired
    private BPNFCLocationDao bpnfcLocationDao;

    @Autowired
    private BpDeviceFacilityCollectionDao facilityCollectionDao;
    @Autowired
    private PatrolDataTypeMapper patrolDataTypeMapper;
    @Autowired
    private BpProductionFacilityService bpProductionFacilityService;
    @Autowired
    private PatrolRecordItemService itemService;


    @Override
    public List<SimplePointRecordDto> appGetPointRecord(Long taskId) {
        List<SimplePointRecordDto> pointRecord = recordMapper.selectSimplePointRecord(taskId);
        pointRecord.forEach(e -> {
            if (e.getExCount() != null && "异常".equals(e.getCheckResult())) {
                e.setResult(e.getExCount()+ "处" +e.getCheckResult());
            }
        });
        return pointRecord;
    }

    @Override
    public List<WebTaskRecordPointVo> webGetPointRecord(Long taskId) {
        List<WebTaskRecordPointVo> pointRecords = recordMapper.selectPointRecord(taskId);
        if (CollectionUtil.isNotEmpty(pointRecords)) {
            pointRecords.forEach(record -> {
                List<WebTaskRecordDeviceVo> deviceList = getItemRecord(record);
                record.setDeviceList(deviceList);
            });
        }
        return pointRecords;
    }

    @Override
    public List<WebTaskRecordDeviceVo> getDeviceRecordByRecordId(Long recordId) {
        WebTaskRecordPointVo record = recordMapper.selectPointRecordByRecordId(recordId);
        return getItemRecord(record);
    }

    private List<WebTaskRecordDeviceVo> getItemRecord(WebTaskRecordPointVo record) {
        // 查询检查点下的所有检查项目。检查点->设备->检查项目，三级结构。
        // 设备冗余在了检查项目中。故此处查出后需分组，将其构造成两级结构
        LambdaQueryWrapper<PatrolRecordItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatrolRecordItem::getRecordId,record.getRecordId());
        wrapper.eq(PatrolRecordItem::getDeleteFlag,DeleteFlag.EFFECTIVE.getCode());
        wrapper.orderByAsc(PatrolRecordItem::getCheckDeviceId);
        List<PatrolRecordItem> recordItems = recordItemService.list(wrapper);
        // 按设备分组，构造两级list
        Map<Long, List<PatrolRecordItem>> deviceGroups = recordItems.stream().collect(Collectors.groupingBy(PatrolRecordItem::getCheckDeviceId));
        List<WebTaskRecordDeviceVo> deviceList = new ArrayList<>();
        // 每个deviceEntry为一个设备，一个设备下有多个检查项目。
        deviceGroups.entrySet().forEach(deviceEntry -> {
            List<PatrolRecordItem> recordItemGroup = deviceEntry.getValue();

            // 设备信息每个检查项目中都有，直接从第一个检查项目中拿
            PatrolRecordItem firstRecordItem = recordItemGroup.get(0);
            Long deviceId = firstRecordItem.getCheckDeviceId();
            // 有设备编号的拼上设备编号
            String nameAndCode = StringUtils.isNotBlank(firstRecordItem.getCheckDeviceCode()) ?
                    firstRecordItem.getCheckDeviceName() +"["+ firstRecordItem.getCheckDeviceCode() +"]"
                    : firstRecordItem.getCheckDeviceName();
            String deviceName = firstRecordItem.getCheckDeviceName();

            // 第一级：设备
            WebTaskRecordDeviceVo deviceVo = new WebTaskRecordDeviceVo(firstRecordItem.getId(), deviceId, deviceName, nameAndCode);
            ArrayList<WebTaskRecordItemVo> itemVos = new ArrayList<>();
            // 第二级：检查项目
            recordItemGroup.forEach(item -> {
                WebTaskRecordItemVo itemVo = new WebTaskRecordItemVo();
                boolean needUnit = !Constants.DEVICE_STOP_NO_CHECK.equals(item.getCheckResult())
                        && !Constants.DEVICE_STOP_NO_CHECK.equals(item.getCheckResult1())
                        && !Constants.DEVICE_STOP_NO_CHECK.equals(item.getCheckResult2());
                itemVo.setRecordItemId(item.getId())
                        .setCheckItemId(item.getCheckProjectId())
                        .setCheckItemName(item.getCheckProjectName())
                        .setCheckStandard(item.getCheckStandard())
                        .setCheckResult(item.getCheckResult())
                        .setCheckResult1(item.getCheckResult1())
                        .setCheckResult2(item.getCheckResult2())
                        .setCheckResultUnit(item.getCheckResultUnit())
                        .setCheckResultUnit1(item.getCheckResultUnit1())
                        .setCheckResultUnit2(item.getCheckResultUnit2())
                        .setCheckResultState(item.getCheckResultState())
                        .setResultType(item.getResultType())
                        .setExceptHandel(item.getExceptHandel())
                        .setRemark(item.getRemark())
                        .setNeedUnit(needUnit);
                setMediaUrls(item ,itemVo);
                itemVos.add(itemVo);
            });
            itemVos.sort(Comparator.comparing(WebTaskRecordItemVo::getCheckItemId));
            deviceVo.setItemList(itemVos);
            deviceList.add(deviceVo);
        });
        deviceList.sort(Comparator.comparing(WebTaskRecordDeviceVo::getCheckDeviceId));
        return deviceList;
    }


    /**
     * 将ids(1,2,3...)转化为前端使用的下载url
     * @param resource
     * @param target
     */
    private void setMediaUrls(PatrolRecordItem resource,WebTaskRecordItemVo target) {
        // 文件下载路径前缀，视频、录音
        String fp = Constant.FILE_DOWNLOAD_URL_PREFIX;
        // 图片下载路径前缀
        String mp = Constant.IMG_DOWNLOAD_URL_PREFIX;
        String voiceJson = resource.getVoiceJson();
        String videoJson = resource.getVideoJson();
        String picJson = resource.getPicJson();
        if (StringUtils.isNotBlank(voiceJson)) {
            List<String> voiceIds = Splitter.on(Constant.SPLIT_COMMA).trimResults().splitToList(voiceJson);
            List<String> voiceUrls = voiceIds.stream().map(e -> fp+e).collect(Collectors.toList());
            target.setVoiceUrls(voiceUrls);
        }
        if (StringUtils.isNotBlank(videoJson)) {
            List<String> videoIds = Splitter.on(Constant.SPLIT_COMMA).trimResults().splitToList(videoJson);
            List<String> videoUrls = videoIds.stream().map(e -> fp+e).collect(Collectors.toList());
            target.setVideoUrls(videoUrls);
        }
        if (StringUtils.isNotBlank(picJson)) {
            List<String> picIds = Splitter.on(Constant.SPLIT_COMMA).trimResults().splitToList(picJson);
            List<String> picUrls = picIds.stream().map(e -> mp+e).collect(Collectors.toList());
            target.setPicUrls(picUrls);
        }
    }

    @Override
    public List<PatrolCheckPoint> getUncheckPointByTaskId(Long taskId) {
        return recordMapper.selectUncheckPoint(taskId);
    }

    @Override
    public List<PatrolCheckItem> getCheckItemByPointId(Long pointId) {
        LambdaQueryWrapper<PatrolCheckItem> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatrolCheckItem::getDeleteFlag, DeleteFlag.EFFECTIVE.getCode());
        wrapper.eq(PatrolCheckItem::getPointId, pointId);
        List<PatrolCheckItem> items = checkItemService.list(wrapper);
        return items;
    }

    @Override
    public List<SnapshotVo> getSnapshot(Long taskId, String checkUserNames) {
        LambdaQueryWrapper<PatrolRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatrolRecord::getTaskId,taskId);
        wrapper.eq(PatrolRecord::getDeleteFlag, DeleteFlag.EFFECTIVE.getCode());
        List<PatrolRecord> records = list(wrapper);
        List<SnapshotVo> snapshotVos = convertToSnapshot(records, checkUserNames);
        return snapshotVos;
    }

    List<SnapshotVo> convertToSnapshot(List<PatrolRecord> records, String checkUserNames) {
        if (CollectionUtil.isEmpty(records)) {
            return new ArrayList<>();
        }
        ArrayList<SnapshotVo> snapshotVos = new ArrayList<>();
        records.forEach(record -> {
            SnapshotVo snapshotVo = new SnapshotVo();
            String npcLocation = null;
            CheckPointDetailVo pointDetailVo = pointService.getPointById(record.getPointId());
            if (pointDetailVo != null) {
                String nfc = pointDetailVo.getNfc();
                if (nfc != null) {
                    BPNFCLocation cardBean = bpnfcLocationDao.findFirstByCode(nfc);
                    if (cardBean != null) {
                        npcLocation = cardBean.getLocation();
                    }

                }
            }

            snapshotVo.setRecordId(record.getId())
                    .setPointId(record.getPointId())
                    .setPointName(record.getPointName())
                    .setPointLocation(StringUtils.isNotEmpty(npcLocation) ? npcLocation : pointService.getLocationById(record.getPointId()))
                    .setCheckUserName(checkUserNames)
                    .setCheckDate(record.getCheckEndTime())
                    .setConclusion(calculateConclusion(record))
                    .setCheckLocation(record.getVerifyLocation())
                    .setUncheckFlag("漏检".equals(record.getCheckResult()));
            snapshotVos.add(snapshotVo);
        });
        return snapshotVos;
    }

    private String searchNpcLocation(PatrolRecord record) {
        BaseNfcCardBean cardBean = bpNFCLocationService.getById(record.getPointId());
        if (cardBean != null) {
            return cardBean.getLocation();
        }
        return null;
    }

    String calculateConclusion(PatrolRecord record) {
        String conclusion = "正常";
        Set<String> itemExcSet = new HashSet<>();
        Set<String> recordExcSet = new HashSet<>();
        if ("漏检".equals(record.getCheckResult())) {
            conclusion = "异常";
            recordExcSet.add("漏检");
        }else {

            LambdaQueryWrapper<PatrolRecordItem> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(PatrolRecordItem::getRecordId,record.getId());
            wrapper.eq(PatrolRecordItem::getDeleteFlag,DeleteFlag.EFFECTIVE.getCode());
            List<PatrolRecordItem> items = recordItemService.list(wrapper);
            // 提取recordItem的异常信息
            items.forEach(item -> {
                if (StringUtils.isNotBlank(item.getExcepInfo())) {
                    itemExcSet.addAll(Splitter.on(Constant.SPLIT_COMMA).trimResults().splitToList(item.getExcepInfo()));
                }
            });
            // 转化异常信息
            if (CollectionUtil.isNotEmpty(itemExcSet)) {
                conclusion = "异常";
                if (itemExcSet.contains("发现异常")) {
                    recordExcSet.add("数据异常");
                }
                if (itemExcSet.contains("签到异常")) {
                    recordExcSet.add("未到位");
                }
                if (itemExcSet.contains("补检")) {
                    recordExcSet.add("补检");
                }
                if (itemExcSet.contains("未检")) {
                    recordExcSet.add("漏检");
                }
            }
        }
        // 拼接检查结果和异常信息
        if (recordExcSet.size() > 0) {
            String expStr = recordExcSet.stream().collect(Collectors.joining(Constant.SPLIT_COMMA));
            conclusion = new StringBuilder()
                            .append(conclusion)
                            .append(Constant.EN_LEFT_BRACKETS)
                            .append(expStr)
                            .append(Constant.EN_RIGHT_BRACKETS)
                            .toString();
        }
        return conclusion;
    }

    @Override
    public List<PointRecordVo> appGetCheckPointByTaskId(Long taskId) {
        LambdaQueryWrapper<PatrolRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatrolRecord::getTaskId,taskId);
        wrapper.eq(PatrolRecord::getDeleteFlag, DeleteFlag.EFFECTIVE.getCode());
        List<PatrolRecord> records = list(wrapper);
        return convertToPointRecordVo(records);
    }


    private List<PointRecordVo> convertToPointRecordVo(List<PatrolRecord> records) {
        ArrayList<PointRecordVo> result = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(records)) {
            records.forEach(record -> {
                PointRecordVo recordVo = new PointRecordVo();
                recordVo.setRecordId(record.getId())
                        .setPointId(record.getPointId())
                        .setCheckEndTime(record.getCheckEndTime())
                        .setPointName(record.getPointName())
                        .setVerifyState(record.getVerifyState())
                        .setCheckResult(record.getCheckResult());
                String checkResult = record.getCheckResult();
                if ("异常".equals(checkResult) && record.getExceptCount() != null) {
                    recordVo.setCheckResult(record.getExceptCount() + "处" + checkResult);
                }
                result.add(recordVo);
            });
        }
        return result;
    }

    public boolean deleteTaskRecord(Long taskId) {
        boolean flag;
        // 删除任务
        PatrolTask task = taskService.getById(taskId);
        task.setDeleteFlag(DeleteFlag.DELETED.getCode());
        flag = taskService.saveOrUpdate(task);

        // 删除record
        LambdaQueryWrapper<PatrolRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(PatrolRecord::getTaskId,taskId);
        List<PatrolRecord> records = list(wrapper);
        if (CollectionUtil.isNotEmpty(records)) {
            ArrayList<Long> recordIds = new ArrayList<>();
            records.forEach(record -> {
                record.setDeleteFlag(DeleteFlag.DELETED.getCode());
                recordIds.add(record.getId());
            });
            saveOrUpdateBatch(records);

            // 删除recordItem
            LambdaQueryWrapper<PatrolRecordItem> itemWrapper = new LambdaQueryWrapper<>();
            itemWrapper.in(PatrolRecordItem::getRecordId,recordIds);
            List<PatrolRecordItem> itemList = recordItemService.list(itemWrapper);
            if (CollectionUtil.isNotEmpty(itemList)) {
                itemList.forEach(item -> item.setDeleteFlag(DeleteFlag.DELETED.getCode()));
                recordItemService.saveOrUpdateBatch(itemList);
            }
        }
        return flag;
    }

    @Override
    public List<SimpleRecordResultDto> getSimpleRecordsByPlanIds(List<Long> planIds, StatPlanTitleSearchBean searchBean) {
        return recordMapper.selectSimpleRecordByPlanIds(planIds, searchBean);
    }

    /**
     * 生成记录（record、recordItem）
     * @param point 检查点
     * @param task 巡检任务
     * @param deviceStopAutoProcess 设备停用是否自动处理巡检任务 1-自动处理 0-不自动处理
     * @return 检查点检查结果 CheckResultStatus
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String genRecordByPoint(PatrolCheckPoint point, PatrolTask task, String deviceStopAutoProcess) {
        PatrolRecord record = new PatrolRecord();
        Date currDate = new Date();
        record.setTaskId(task.getId())
                .setPlanId(task.getPlanId())
                .setPointId(point.getId())
                .setCheckResult(CheckResultStatus.UNCHECK)
                .setPointName(point.getCheckPointName())
                .setCheckStartTime(currDate)
                .setCheckEndTime(currDate);
        record.setTenentId(point.getTenentId());
        record.setOrgCode(point.getOrgCode());
        this.save(record);
        List<PatrolCheckItem> checkItems = this.getCheckItemByPointId(point.getId());
        ArrayList<PatrolRecordItem> recordItems = new ArrayList<>();
        checkItems.forEach(each -> {
            PatrolRecordItem recordItem = new PatrolRecordItem();
            Optional<BpDeviceFacilityCollection> deviceOpt = facilityCollectionDao.findById(each.getDeviceId());
            if (deviceOpt.isPresent()) {
                BpDeviceFacilityCollection device = deviceOpt.get();
                recordItem.setRecordId(record.getId())
                        .setCheckResultState(CheckResultStatus.UNCHECK)
                        .setCheckDeviceId(each.getDeviceId())
                        .setCheckDeviceName(device.getName())
                        .setCheckDeviceCode(device.getCode())
                        .setCheckProjectId(each.getId())
                        .setCheckProjectName(each.getCheckItem())
                        .setCheckStandard(each.getCheckStandard())
                        .setResultType(each.getDataType())
                        .setExcepInfo("未检");
                if (DataTypeEnum.SHOCK.getValue().equals(each.getDataType())) {
                    String dataTypeName = patrolDataTypeMapper.findNameById(each.getDataTypeId());
                    recordItem.setSubResultType(dataTypeName);
                }
                // 巡检计划开启设备停用自动处理
                if (Constant.COMMON_SWITCH_ON.equals(deviceStopAutoProcess) && device.getDeviceId() != null) {
                    BpProductionFacility productionFacility = bpProductionFacilityService.findOne(device.getDeviceId());
                    // 设备停用
                    if (productionFacility != null && ProductionFacilityStates.STOPED.getId() == productionFacility.getState()) {
                        recordItem.setCheckResultState(CheckResultStatus.NORMAL);
                        recordItem.setCheckResult(Constants.DEVICE_STOP_NO_CHECK);
                        recordItem.setExcepInfo("");
                    }
                }
                recordItems.add(recordItem);
            }
        });
        if (CollectionUtil.isNotEmpty(recordItems)) {
            itemService.saveBatch(recordItems);
            // 若设备均停用无需检查，则巡检记录的状态也是正常
            long unNormalNum = recordItems.stream().filter(item -> !CheckResultStatus.NORMAL.equals(item.getCheckResultState())).count();
            if (unNormalNum == 0) {
                record.setCheckResult(CheckResultStatus.NORMAL);
                this.saveOrUpdate(record);
            }
        }
        return record.getCheckResult();
    }

}
